#ifndef DOXYGEN_IGNORE_ADVANCED

#include <GameEngine/Graphics/renderbuffer_object.h>

#include <GameEngine/Graphics/openGL.h>



#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

GAMEENGINE_IMPLEMENT_RTTI(RenderbufferObject)


//! Default constructor
RenderbufferObject::RenderbufferObject() : id_(0), GraphicResource() {
	create_id();
}

//! Copy constructor
/*!
 @param rhs The renderbuffer object to copy
 */
RenderbufferObject::RenderbufferObject(const RenderbufferObject& rhs) : id_(rhs.id_), GraphicResource() {
	if ( id_ ) ResourceManager<ID,CONTEXTID>::instance()->reference_resource(*this);
}

//! Destructor
RenderbufferObject::~RenderbufferObject() {
	clean_id();
}

//! Assignment operator
/*!
 @param rhs The renderbuffer object to copy
 */
RenderbufferObject& RenderbufferObject::operator=(const RenderbufferObject& rhs) {
	if ( &rhs != this ) {
		ResourceManager<ID,CONTEXTID>* manager = (ResourceManager<ID,CONTEXTID>*)ResourceManager<ID,CONTEXTID>::instance();
		if ( id_ ) manager->unreference_resource(*this);
		id_ = rhs.id_;
		if ( id_ ) manager->reference_resource(*this);
	}
	return *this;
}

//! Check if the renderbuffer object has been allocated
/*!
 @return True if the renderbuffer object has been allocated, false otherwise
 */
bool RenderbufferObject::initialized() const {
	return ( id_ != 0 );
}

//! Try to bind the renderbuffer object
/*!
 @return True if renderbuffer object could be bound, false otherwise
 */
bool RenderbufferObject::bind_buffer() const {
	if ( id_ == 0 ) return false;
	if ( glBindRenderbufferEXT == nil ) return false;
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id_);
	return true;
}

//! Try to unbind the renderbuffer object
/*!
 @return True if renderbuffer object could be unbound, false otherwise
 */
bool RenderbufferObject::unbind_buffer() const {
	if ( glBindRenderbufferEXT == nil ) return false;
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
	return true;
}

//! Set the storage mode for the renderbuffer
/*!
 *  Renderbuffer should be bound for the parameters to take effect. Please note, however, that this
 *  function does NOT check if renderbuffer is bound or not.
 *
 @param width The width of the renderbuffer
 @param height The height of the renderbuffer
 @param format The format of internal storage for the renderbuffer
 @return True if the storage of the renderbuffer object could be setup, false otherwise
 */
bool RenderbufferObject::set_storage(RenderbufferSize width, RenderbufferSize height, Format format) {
	if ( id_ == 0 ) return false;
	if ( glRenderbufferStorageEXT == nil ) return false;
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, width, height);
	return true;
}

//! Return the OpenGL ID of the renderbuffer
/*!
 *  This ID should NOT be deleted using the glDeleteRenderbuffersEXT() function, since the
 *  renderbuffer class takes care of its own memory and desallocates the renderbuffer when
 *  there are no more users on it.
 */
RenderbufferObject::ID RenderbufferObject::id() const {
	return id_;
}

//! Clean the previous ID
void RenderbufferObject::clean_id() {
	// Nothing to do if ID is not allocated
	if ( id_ == 0 ) return;

	// Unreference ID from the resource manager
	ResourceManager<ID,CONTEXTID>::instance()->unreference_resource(*this);

	// Clean ID member variable
	id_ = 0;
}

//! Allocate a new ID
void RenderbufferObject::create_id() {
	// Clean previous ID, if any
	clean_id();

	// Generate a new renderbuffer object ID
	glGenRenderbuffersEXT(1, &id_);

	// Reference this ID
	ResourceManager<ID,CONTEXTID>::instance()->reference_resource(*this);
}

//! Desallocate the renderbuffer object ID
void RenderbufferObject::destroy_resource() const {
	glDeleteRenderbuffersEXT(1, &id_);
}

//! Return the renderbuffer object context
RenderbufferObject::CONTEXTID RenderbufferObject::context() const {
	return rtti_id_;
}

//! Return the renderbuffer object reference
RenderbufferObject::ID RenderbufferObject::reference() const {
	return id_;
}

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
